#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <termios.h>
#include <stropts.h>
#include <sys/ioctl.h>
#include <pthread.h>


#include "estructuras.h"
#include "constantes.h"
#include "listas.h"
#include "sockets.h"
#include "configuracion.h"
#include "NIPC.h"
#include "hiloDisco.h"


void cargarCHS(int cilindros,int cabezales,int sectores);
int  VerificarCompatibilidad(char *sNombre_NuevoDA , int iCC_NuevoDA, int iHH_NuevoDA , int iSS_NuevoDA);
int VerificarSITodosLosDAEstanListos();
int ConsolaEsperaNuevosDiscos (void * pSocketParaArray);
chs glChs;
extern ListConfig * listaConfig;
extern int owner;

int ConsolaEsperaNuevosDiscos (void * pSocketParaArray)
{

	pthread_t ID_HiloDeDisco;
	int iSocketEscuchaConexiones,iSocketDisco_temporal;
	disco *pNodoDisco,*pAuxDisco;
	char sNombre_NuevoDA[20];
	fd_set set_socketConsola;
	int iCC_NuevoDA,iHH_NuevoDA,iSS_NuevoDA;
	struct sockaddr_in* cliente;
	int address_size=sizeof(struct sockaddr_in);
	pthread_t syncer_id;
	struct DiscoConocido *pDiscoALeer; 
	int sectorASincronizar;
	int pos;
 
	listaConfig = NULL;
	cargarConfig();
	iSocketEscuchaConexiones  = PrepararSocket (puertoConex,obtenerValor("ipLocal"));   
	escuchar(iSocketEscuchaConexiones,10); 

	while(1)
	{
		printf("\nEstado del Array:\r\n");
		switch(Estado)
		{
			case INICIALIZADO:
				printf("INICIALIZADO\r\n");
			break;

			case FUERA_DE_SERVICIO:
				printf("FUERA DE SERVICIO\r\n");
			break;
		}
		switch(SubEstado)
		{
			case SINCRONIZADO:
				printf("SINCRONIZADO\r\n");
			break;

			case INCOMPLETO:
				printf("INCOMPLETO\r\n");
			break;

			case SINCRONIZANDO:
				printf("SINCRONIZANDO\r\n");
			break;
		}
		
		printf("DISCOS CONECTADOS:\n");
		printf("------------------\n");
		pAuxDisco = ListaDiscos;
		if(pAuxDisco == NULL)
			printf("No hay\n");
		while(pAuxDisco != NULL)
		{
          printf("%s\n", pAuxDisco->sNombre );
          pAuxDisco = pAuxDisco->Sgt;	
		} 
		
		FD_ZERO(&set_socketConsola);
		FD_SET(iSocketEscuchaConexiones ,&set_socketConsola);
		select(iSocketEscuchaConexiones+1, &set_socketConsola, NULL, NULL, NULL);	

		if( FD_ISSET(iSocketEscuchaConexiones , &set_socketConsola ) > 0 )
		{
            if((iSocketDisco_temporal = accept(iSocketEscuchaConexiones,(struct sockaddr*)&cliente,&address_size))== -1) 
               return ERRORACCEPT;	

				
			/*Handshake de disco*/
			InfoIPC infoIPC;
			recibirIPC(iSocketDisco_temporal,&infoIPC);
            strcpy(sNombre_NuevoDA,infoIPC.payload);
			free(infoIPC.payload);
			
			InfoIPC infoIPC2;
			infoIPC2.payLoadLength=5;
			generarStructIPC("nada",HSOK,&infoIPC2);
			enviarIPC(iSocketDisco_temporal,&infoIPC2);
			free(infoIPC2.payload);
			
			InfoIPC infoIPC3;
			recibirIPC(iSocketDisco_temporal,&infoIPC3);
            iCC_NuevoDA = atoi(infoIPC3.payload);
			free(infoIPC3.payload);
            
			InfoIPC infoIPC4;
			recibirIPC(iSocketDisco_temporal,&infoIPC4);
            iHH_NuevoDA = atoi(infoIPC4.payload);
            free(infoIPC4.payload);
			
			
			InfoIPC infoIPC5;
			recibirIPC(iSocketDisco_temporal,&infoIPC5);
            iSS_NuevoDA = atoi(infoIPC5.payload);
			free(infoIPC5.payload);
			
			
		 
				 
            if(SubEstado!=INCOMPLETO) {
				
				
				if( INCOMPATIBLE == VerificarCompatibilidad(sNombre_NuevoDA , iCC_NuevoDA, iHH_NuevoDA, iSS_NuevoDA ) )  
				{
				   InfoIPC infoIPC6;
				   infoIPC6.payLoadLength=5;
				   generarStructIPC("nada", DA_INCOMPATIBLE,&infoIPC6);	
				   enviarIPC(iSocketDisco_temporal,&infoIPC6);   
				   free(infoIPC6.payload);
				   cerrarSocket(iSocketDisco_temporal);		
				   printf("Disco Incompatble.Se cierra la conexion con RAID.\n");
				   continue;
				}
				 
			}
	  
			printf("\nSe conecto: %s\n", sNombre_NuevoDA);   
			
            pNodoDisco = malloc( sizeof(struct DiscoConocido) );
            strcpy(pNodoDisco->sNombre , sNombre_NuevoDA);
            pNodoDisco->iSocketHDAParaDA = iSocketDisco_temporal;
			pNodoDisco->listaPedidos = colaGlobal;
            pNodoDisco->listaPedidos_Ult = colaGlobal_Ult;
			pNodoDisco->pendings = 0;
			pNodoDisco->Sgt = NULL;
            pNodoDisco->Ant = NULL;
			
            if(SubEstado == INCOMPLETO) { 
				pNodoDisco->Estado = LISTO;					
			}
			else{
				pNodoDisco->Estado = SINCRONIZANDO;
			}	
 
			/*Le informo al PPD que la conexion se dio de manera satisfactoria*/ 
			InfoIPC infoIPC7;
			infoIPC7.payLoadLength=5;
            generarStructIPC("nada", DA_CONECTADO_CORRECTAMENTE,&infoIPC7);	
            enviarIPC(pNodoDisco->iSocketHDAParaDA,&infoIPC7); 	
			free(infoIPC7.payload);
			/*Agrego a lista de disco*/
			agregarAListaDeDiscos(&pNodoDisco);
			
			if(SubEstado == INCOMPLETO)
            {
				SubEstado = SINCRONIZADO;
				Estado = INICIALIZADO;
				InfoIPC infoIPC8;
				infoIPC8.payLoadLength=5;
				generarStructIPC("nada", INICIALIZADO,&infoIPC8);
				cargarCHS(iCC_NuevoDA,iHH_NuevoDA,iSS_NuevoDA);
				printf("\nRAID OPERACIONAL!!!\n", sNombre_NuevoDA,iSocketDisco_temporal);  
				enviarIPC( *(int *)pSocketParaArray,&infoIPC8); /*Ya se conecto un disco:el array pasa a estar operacional.RAID OPERACIONAL*/
				free(infoIPC8.payload);
            }	
			
			iCantidadDeDAConectados++;
            printf("Cantidad de PPD conectados %i \n",iCantidadDeDAConectados);
			pthread_create(&ID_HiloDeDisco,NULL,(void*)HiloDeDisco ,(void *)pNodoDisco);	/*se crea el hilo que va a estar comunicado al disco que se agrego*/	
			
			/*
			if(pNodoDisco->Estado == SINCRONIZANDO)
			{
				pDiscoALeer = BuscarDiscoListo();  
				if(pDiscoALeer==NULL){
					printf("No hay disco disponible para realizar la sincronizacion \n");		
				}	
				else{
					
					
					sectorASincronizar=0;
					SubEstado = SINCRONIZANDO;
					pDiscoALeer->Estado = SINCRONIZANDO_LEYENDO;
					while(sectorASincronizar< 100)
					{
						asignarread(pDiscoALeer,sectorASincronizar,1);   
						sectorASincronizar++;
					}
				
					
					pos=insertar(pDiscoALeer,pNodoDisco);
					VectorSincronizacion[pos].sectoresRecibidos=0;
					VectorSincronizacion[pos].sectoresEnviados=99;
					sectorASincronizar=0;
					SubEstado = SINCRONIZANDO;
					pDiscoALeer->Estado = SINCRONIZANDO_LEYENDO;
					
					while(sectorASincronizar< 100)
					{
						asignarread(VectorSincronizacion[pos].discoLect,sectorASincronizar,pos);   
						sectorASincronizar++;
					}	

				}        	
			}
			*/
			pNodoDisco->Estado = LISTO;
			
		}       
	}
	cerrarSocket(iSocketEscuchaConexiones);
}

int  VerificarCompatibilidad(char *sNombre_NuevoDA , int iCC_NuevoDA, int iHH_NuevoDA , int iSS_NuevoDA)  /*verificar si el nombre y la cantidad de sectores coincide con lo pasado por archivo config, tmb verificar si ya se conecto un disco con ese nombre*/
{
	int i;  
	disco *pAuxDisco;
	
	
	/*Me fijo si ya existe un disco con ese nombre en la lista de discos*/	
	pAuxDisco = ListaDiscos;
	while(pAuxDisco != NULL)
	{
		if((strcmp(sNombre_NuevoDA,pAuxDisco->sNombre) == 0))
			return INCOMPATIBLE;
		pAuxDisco = pAuxDisco->Sgt;	
	} 

	/*Me fijo que la cantidad de sectores del disco sea igual a la explicitada por archivo de configuracion*/
	if( (iCC_NuevoDA != glChs.cilindros) || (iHH_NuevoDA != glChs.cabezal) || (iSS_NuevoDA != glChs.sectores) )
		return INCOMPATIBLE; 


	return COMPATIBLE;
}



int VerificarSITodosLosDAEstanListos()
{
    struct DiscoConocido * pAuxDisco;

    pAuxDisco = ListaDiscos;
    while(pAuxDisco != NULL)
    {
	if (pAuxDisco->Estado != LISTO)
	    return FALSO;

	pAuxDisco = pAuxDisco->Sgt;
    }

    return VERDADERO;
}


void cargarCHS(int cilindros,int cabezales,int sectores)
{
	glChs.cilindros = cilindros;
	glChs.cabezal = cabezales;
	glChs.sectores = sectores;
	sectoresTotales=(glChs.cilindros*glChs.cabezal*glChs.sectores) -1;
	
}




